package com.yc.sole.financial.biz;

import cn.hutool.core.collection.CollUtil;
import com.google.common.collect.Lists;
import com.yc.sole.common.constant.PubConstant;
import com.yc.sole.common.domain.StateCountResp;
import com.yc.sole.common.enums.PaymentMethod;
import com.yc.sole.erp.dto.CustomerDto;
import com.yc.sole.erp.dto.SaleOrderDto;
import com.yc.sole.erp.exception.ErpResultEnum;
import com.yc.sole.erp.repository.CustomerRepository;
import com.yc.sole.erp.repository.SaleOrderRepository;
import com.yc.sole.financial.dto.ReceiptDto;
import com.yc.sole.financial.exception.FinancialResultEnum;
import com.yc.sole.financial.repository.ReceiptRepository;
import com.yc.sole.financial.request.ReceiptBatchReq;
import com.yc.sole.financial.request.ReceiptQueryReq;
import com.yc.sole.financial.request.ReceiptReq;
import com.yc.sole.financial.response.ReceiptResp;
import com.yc.sole.framework.exception.BaseException;
import com.yc.sole.framework.mybatis.page.Paging;
import com.yc.sole.system.service.SequenceService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 服务接口实现
 *
 * @author yizuomin
 * @date 2024-03-08
 **/
@Slf4j
@Service
@RequiredArgsConstructor
public class ReceiptBiz {

    private final ReceiptRepository receiptRepository;
    private final SaleOrderRepository saleOrderRepository;
    private final SequenceService sequenceService;
    private final CustomerRepository customerRepository;

    /**
     * 新增
     *
     * @param receiptReq
     */
    @Transactional(rollbackFor = Exception.class)
    public void saveReceipt(ReceiptReq receiptReq) {
        CustomerDto customerDto = customerRepository.selectCustomerById(receiptReq.getCustomerId());
        if (Objects.isNull(customerDto)) {
            throw new BaseException(ErpResultEnum.CUSTOMER_NOT_FOUND);
        }
        SaleOrderDto saleOrderDto = saleOrderRepository.selectSaleOrderById(receiptReq.getOrderId());
        if (Objects.isNull(saleOrderDto)) {
            throw new BaseException(ErpResultEnum.SALE_ORDER_NOT_FOUND);
        }
        // 判断订单是否已全部付款
        if (saleOrderDto.getPaidAmount().compareTo(saleOrderDto.getAmount()) == 0) {
            throw new BaseException(FinancialResultEnum.ORDER_IS_PAID);
        }
        ReceiptDto dto = new ReceiptDto();
        // 生成收款编号
        String receiptNo = sequenceService.generateSeqNo(PubConstant.RECEIPT_SEQ_KEY);
        dto.setReceiptNo(receiptNo);
        dto.setCustomerId(customerDto.getId());
        dto.setCustomerName(customerDto.getCustomerName());
        dto.setOrderId(saleOrderDto.getId());
        dto.setOrderNo(saleOrderDto.getOrderNo());
        dto.setAmount(receiptReq.getAmount());
        dto.setReceiptDate(receiptReq.getReceiptDate());
        dto.setReceiptMethod(receiptReq.getReceiptMethod());
        dto.setRemark(receiptReq.getRemark());
        receiptRepository.saveReceipt(dto);
        // 增加订单已付款金额
        saleOrderRepository.updatePaidAmount(saleOrderDto.getId(), receiptReq.getAmount());
    }

    /**
     * 新增
     *
     * @param batchReq
     */
    @Transactional(rollbackFor = Exception.class)
    public void saveBatchReceipt(ReceiptBatchReq batchReq) {
        CustomerDto customerDto = customerRepository.selectCustomerById(batchReq.getCustomerId());
        if (Objects.isNull(customerDto)) {
            throw new BaseException(ErpResultEnum.CUSTOMER_NOT_FOUND);
        }
        Set<Long> orderIds = batchReq.getDataList().stream().map(ReceiptBatchReq.ReceiptBatchDetailReq::getOrderId).collect(Collectors.toSet());
        List<SaleOrderDto> saleOrderDtoList = saleOrderRepository.selectSaleOrderByIds(orderIds);
        if (CollUtil.isEmpty(saleOrderDtoList)) {
            throw new BaseException(ErpResultEnum.SALE_ORDER_NOT_FOUND);
        }
        Map<Long, SaleOrderDto> saleOrderDtoMap = saleOrderDtoList.stream().collect(Collectors.toMap(SaleOrderDto::getId, v -> v));
        for (ReceiptBatchReq.ReceiptBatchDetailReq detailReq : batchReq.getDataList()) {
            SaleOrderDto saleOrderDto = saleOrderDtoMap.get(detailReq.getOrderId());
            // 判断订单是否已全部付款
            if (saleOrderDto.getPaidAmount().compareTo(saleOrderDto.getAmount()) == 0) {
                throw new BaseException(FinancialResultEnum.ORDER_IS_PAID);
            }
            ReceiptDto dto = new ReceiptDto();
            // 生成收款编号
            String receiptNo = sequenceService.generateSeqNo(PubConstant.RECEIPT_SEQ_KEY);
            dto.setReceiptNo(receiptNo);
            dto.setCustomerId(customerDto.getId());
            dto.setCustomerName(customerDto.getCustomerName());
            dto.setOrderId(saleOrderDto.getId());
            dto.setOrderNo(saleOrderDto.getOrderNo());
            dto.setAmount(detailReq.getAmount());
            dto.setReceiptDate(batchReq.getReceiptDate());
            dto.setReceiptMethod(batchReq.getReceiptMethod());
            dto.setRemark(detailReq.getRemark());
            receiptRepository.saveReceipt(dto);
            // 增加订单已付款金额
            saleOrderRepository.updatePaidAmount(saleOrderDto.getId(), detailReq.getAmount());
        }
    }

    /**
     * 修改
     *
     * @param receiptReq
     */
    @Transactional(rollbackFor = Exception.class)
    public void updateReceiptById(ReceiptReq receiptReq) {
        ReceiptDto receiptDto = receiptRepository.selectReceiptById(receiptReq.getId());
        if (Objects.isNull(receiptDto)) {
            throw new BaseException(FinancialResultEnum.RECEIPT_NOT_FOUND);
        }
        ReceiptDto dto = new ReceiptDto();
        dto.setId(receiptDto.getId());
        dto.setAmount(receiptReq.getAmount());
        dto.setReceiptDate(receiptReq.getReceiptDate());
        dto.setReceiptMethod(receiptReq.getReceiptMethod());
        dto.setRemark(receiptReq.getRemark());
        receiptRepository.updateReceiptById(dto);
        // 如果修改过金额，则需要修改订单已收款金额
        if (receiptDto.getAmount().compareTo(receiptReq.getAmount()) != 0) {
            // 增加或减少订单已付款金额
            saleOrderRepository.updatePaidAmount(receiptDto.getOrderId(), receiptReq.getAmount().subtract(receiptDto.getAmount()));
        }
    }


    /**
     * 通过id批量删除
     *
     * @param ids
     */
    @Transactional(rollbackFor = Exception.class)
    public void deleteReceiptByIds(Set<Long> ids) {
        List<ReceiptDto> receiptDtoList = receiptRepository.selectReceiptByIds(ids);
        for (ReceiptDto receiptDto : receiptDtoList) {
            SaleOrderDto saleOrderDto = saleOrderRepository.selectSaleOrderById(receiptDto.getOrderId());
            if (Objects.nonNull(saleOrderDto)) {
                // 减少订单已付款金额
                saleOrderRepository.updatePaidAmount(receiptDto.getOrderId(), receiptDto.getAmount().negate());
            }
        }
        receiptRepository.deleteReceiptByIds(ids);
    }

    /**
     * 根据id查询
     *
     * @param id
     * @return
     */
    public ReceiptResp selectReceiptById(Long id) {
        return receiptRepository.selectReceiptDetailById(id);
    }

    /**
     * 分页查询
     *
     * @param page
     * @param receiptQueryReq
     * @return
     */
    public Paging<ReceiptResp> selectReceiptPage(Paging<ReceiptQueryReq> page, ReceiptQueryReq receiptQueryReq) {
        return receiptRepository.selectReceiptPage(page, receiptQueryReq);
    }

    /**
     * 查询收款方式的数量
     *
     * @param queryReq
     * @return
     */
    public List<StateCountResp> selectReceiptMethodCount(ReceiptQueryReq queryReq) {
        List<StateCountResp> countRespList = receiptRepository.selectReceiptMethodCount(queryReq);
        Long totalCount = countRespList.stream().map(StateCountResp::getCount).reduce(0L, Long::sum);
        ArrayList<StateCountResp> resultList = Lists.newArrayList(new StateCountResp("-1", "全部", totalCount));
        Map<String, StateCountResp> stateCountRespMap = countRespList.stream().collect(Collectors.toMap(StateCountResp::getState, v -> v));
        List<StateCountResp> respList = Arrays.stream(PaymentMethod.values()).map(state -> {
            StateCountResp countResp = stateCountRespMap.get(state.getValue());
            if (Objects.isNull(countResp)) {
                countResp = new StateCountResp();
                countResp.setCount(0L);
            }
            countResp.setStateName(state.getDescription());
            countResp.setState(state.getValue());
            return countResp;
        }).toList();
        resultList.addAll(respList);
        return resultList;
    }
}
